package cn.org.donald.framework.config;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;


/**
 * Injection a thread pool to spring IOC which can make three concurrent task,
 * but you could not shut it down!
 * @author : Donald
 * @since : 2021/1/11 10:07
 */
@Component
public class ServiceThreadPool {

    private static Logger logger = LoggerFactory.getLogger(ServiceThreadPool.class);

    private static volatile ExecutorService executorService;

    private static int freeTime = 0;

    /**
     * Submit the fixed thread pool,
     * if you want to testify the task result, you should use it,
     * if not, you should use execute{@link ServiceThreadPool#execute(Runnable)}.
     * @param runnable implement Runnable
     * @return result of the task
     */
    public synchronized Future<?> submit(Runnable runnable){
        this.createSingleInstanceThreadPool();
        return executorService.submit(runnable);
    }

    /**
     * Execute the fixed thread pool (not return value),
     * if you want to testify the result of task, you can use submit{@link ServiceThreadPool#submit(Runnable)}.
     * @param runnable implement Runnable
     */
    public synchronized void execute(Runnable runnable){
        this.createSingleInstanceThreadPool();
        executorService.execute(runnable);
    }


    /**
     * Listen to the fixed thread pool for shut it down if it has free 10 seconds.
     */
    static class ListenerThread implements Runnable{
        @Override
        public void run() {
            while (true){
                freeTime += 1;
                if (freeTime > 10){
                    executorService.shutdown();
                    while (true){
                        if (executorService.isTerminated()){
                            break;
                        }
                    }
                    executorService = null;
                    break;
                }
                try {
                    Thread.sleep(1000);
                }catch (Exception e){
                    logger.warn("Thread sleep has thrown an exception!");
                }
            }
        }
    }

    /**
     * Create a ExecutorService instance if it is null.
     * Set freeTime to zero when the procedure use this method.
     */
    private synchronized void createSingleInstanceThreadPool(){
        freeTime = 0;
        if (executorService == null){
            logger.debug("Create a new thread pool!");
            new Thread(new ListenerThread()).start();
            executorService = Executors.newFixedThreadPool(3);
        }
    }
}


